<!--
 The BSD 3-Clause License

 Copyright 2022 - DATATRONiQ GmbH (https://datatroniq.com)
 Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
 Copyright 2013, 2016 IBM Corp. (node-red)
 All rights reserved.
 node-red-contrib-iiot-opcua
-->

<style>
    .opcuaiiotinject-time-row {
        padding-left: 110px
    }

    .opcuaiiotinject-time-row select {
        margin: 3px 0
    }

    .opcuaiiotinject-time-days label {
        -webkit-user-select: none;
        -khtml-user-select: none;
        -moz-user-select: none;
        -ms-user-select: none;
        user-select: none;
        vertical-align: top;
        width: 100px
    }

    .opcuaiiotinject-time-days input {
        width: auto
    }

    .opcuaiiotinject-time-times {
        width: 90px
    }

    #opcuaiiotinject-time-time {
        width: 75px
    }

    .opcuaiiotinject-time-count {
        width: 40px !important
    }
</style>

<script type="text/javascript">
  RED.nodes.registerType('OPCUA-IIoT-Inject', {
    category: 'IIoT',
    color: '#ABCDEF',
    defaults: {
      injectType: {value: 'inject'},
      payload: {
        value: '', validate: function (v) {
          let ptype = $('#node-input-payloadType').val() || this.payloadType
          if (ptype === 'json') {
            try {
              JSON.parse(v)
              return true
            } catch (err) {
              return false
            }
          } else if (ptype === 'flow' || ptype === 'global') {
            return /^[a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]+)*/i.test(v)
          } else if (ptype === 'num') {
            return /^[+-]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)?$/.test(v)
          }
          return true
        }
      },
      payloadType: {value: 'date'},
      topic: {value: ''},
      repeat: {value: ''},
      crontab: {value: ''},
      once: {value: false},
      startDelay: {value: ''},
      name: {value: ''},
      addressSpaceItems: {value: []}
    },
    inputs: 0,
    outputs: 1,
    align: 'left',
    icon: 'icon.png'
  })

  let injectNode = RED.nodes.registry.getNodeType('OPCUA-IIoT-Inject')
  injectNode.button = {
    onclick: function () {
      let label = (this.name || this.payload).replace(/&/g, '&amp').replace(/</g, '&lt').replace(/>/g, '&gt')

      if (this.payloadType === 'date') {
        label = this._('opcuaiiotinject.timestamp')
      }

      if (this.payloadType === 'none') {
        label = this._('opcuaiiotinject.blank')
      }

      let node = this

      $.ajax({
        url: 'opcuaIIoT/inject/' + this.id,
        type: 'POST',
        success: function (resp) {
          RED.notify(node._('opcuaiiotinject.success', {label: label}), 'success')
        },
        error: function (jqXHR, textStatus, errorThrown) {
          if (jqXHR.status === 404) {
            RED.notify(node._('common.notification.error', {message: node._('common.notification.errors.not-deployed')}), 'error')
          } else if (jqXHR.status === 500) {
            RED.notify(node._('common.notification.error', {message: node._('opcuaiiotinject.errors.failed')}), 'error')
          } else if (jqXHR.status === 0) {
            RED.notify(node._('common.notification.error', {message: node._('common.notification.errors.no-response')}), 'error')
          } else {
            RED.notify(node._('common.notification.error', {
              message: node._('common.notification.errors.unexpected', {
                status: jqXHR.status,
                message: textStatus
              })
            }), 'error')
          }
        }
      })
    }
  }
  injectNode.oneditprepare = function () {
    let node = this
    let fieldPayloadType = $('#node-input-payloadType')

    if (this.payloadType === null) {
      if (this.payload === '') {
        this.payloadType = 'date'
      } else {
        this.payloadType = 'str'
      }
    } else if (this.payloadType === 'string' || this.payloadType === 'none') {
      this.payloadType = 'str'
    }

    fieldPayloadType.val(this.payloadType)

    $('#node-input-payload').typedInput({
      default: 'str',
      typeField: fieldPayloadType,
      types: ['flow', 'global', 'str', 'num', 'bool', 'json', 'date']
    })

    $('#opcuaiiotinject-time-type-select').change(function () {
      $('#node-input-crontab').val('')
      let id = $('#opcuaiiotinject-time-type-select').val()

      $('.opcuaiiotinject-time-row').hide()
      $('#opcuaiiotinject-time-row-' + id).show()

      if ((id === 'none') || (id === 'interval')) {
        $('#node-once').show()
        $('#node-delay').show()
      }
      else {
        $('#node-once').hide()
        $('#node-delay').hide()
        $('#node-input-once').prop('checked', false)
      }
    })

    $('.opcuaiiotinject-time-times').each(function () {
      for (let i = 0; i < 24; i++) {
        let l = (i < 10 ? '0' : '') + i + ':00'
        $(this).append($('<option></option>').val(i).text(l))
      }
    })
    $('<option></option>').val(24).text('00:00').appendTo('#opcuaiiotinject-time-interval-time-end')

    $('#opcuaiiotinject-time-interval-time-start').change(function () {
      let start = Number($('#opcuaiiotinject-time-interval-time-start').val())
      let end = Number($('#opcuaiiotinject-time-interval-time-end').val())

      $('#opcuaiiotinject-time-interval-time-end option').remove()

      for (let i = start + 1; i < 25; i++) {
        let l = (i < 10 ? '0' : '') + i + ':00'
        if (i === 24) {
          l = '00:00'
        }
        let opt = $('<option></option>').val(i).text(l).appendTo('#opcuaiiotinject-time-interval-time-end')
        if (i === end) {
          opt.attr('selected', 'selected')
        }
      }
    })

    $('.opcuaiiotinject-time-count').spinner({
      min: 1
    })

    $.widget('ui.injecttimespinner', $.ui.spinner, {
      options: {
        // seconds
        step: 60 * 1000,
        // hours
        page: 60
      },
      _parse: function (value) {
        if (typeof value === 'string') {
          // already a timestamp
          if (Number(value) === value) {
            return Number(value)
          }
          let p = value.split(':')
          let offset = new Date().getTimezoneOffset()
          return ((Number(p[0]) * 60) + Number(p[1]) + offset) * 60 * 1000
        }
        return value
      },
      _format: function (value) {
        let d = new Date(value)
        let h = d.getHours()
        let m = d.getMinutes()
        return ((h < 10) ? '0' : '') + h + ':' + ((m < 10) ? '0' : '') + m
      }
    })

    $('#opcuaiiotinject-time-time').injecttimespinner()

    let repeattype = 'none'

    if (this.repeat !== '') {
      repeattype = 'interval'

      let units = 's'
      let timeRange = this.repeat

      if (this.repeat % 60 === 0) {
        units = 'm'
        timeRange = timeRange / 60
      }

      if (this.repeat % 1440 === 0) {
        units = 'h'
        timeRange = timeRange / 60
      }

      $('#opcuaiiotinject-time-interval-count').val(timeRange)
      $('#opcuaiiotinject-time-interval-units').val(units)
      $('#opcuaiiotinject-time-interval-days').prop('disabled', 'disabled')

    } else if (this.crontab !== '') {
      let cronparts = this.crontab.split(' ')
      let days = cronparts[4]

      if (!isNaN(cronparts[0]) && !isNaN(cronparts[1])) {
        repeattype = 'time'
        // Fixed time
        let time = cronparts[1] + ':' + cronparts[0]

        $('#opcuaiiotinject-time-time').val(time)
        $('#opcuaiiotinject-time-type-select').val('s')

        if (days === '*') {
          $('#opcuaiiotinject-time-time-days input[type=checkbox]').prop('checked', true)
        } else {
          $('#opcuaiiotinject-time-time-days input[type=checkbox]').removeAttr('checked')
          days.split(',').forEach(function (v) {
            $('#opcuaiiotinject-time-time-days [value=' + v + ']').prop('checked', true)
          })
        }
      } else {
        repeattype = 'interval-time'
        // interval - time period
        let minutes = cronparts[0].slice(2)

        if (minutes === '') {
          minutes = '0'
        }

        $('#opcuaiiotinject-time-interval-time-units').val(minutes)

        if (days === '*') {
          $('#opcuaiiotinject-time-interval-time-days input[type=checkbox]').prop('checked', true)
        } else {
          $('#opcuaiiotinject-time-interval-time-days input[type=checkbox]').removeAttr('checked')

          days.split(',').forEach(function (v) {
            $('#opcuaiiotinject-time-interval-time-days [value=' + v + ']').prop('checked', true)
          })
        }

        let time = cronparts[1]
        let timeparts = time.split(',')
        let start
        let end

        if (timeparts.length === 1) {
          // 0 or 0-10
          let hours = timeparts[0].split('-')

          if (hours.length === 1) {
            if (hours[0] === '') {
              start = '0'
              end = '0'
            }
            else {
              start = hours[0]
              end = Number(hours[0]) + 1
            }
          } else {
            start = hours[0]
            end = Number(hours[1]) + 1
          }
        } else {
          // 23,0 or 17-23,0-10 or 23,0-2 or 17-23,0
          let startparts = timeparts[0].split('-')
          start = startparts[0]

          let endparts = timeparts[1].split('-')
          if (endparts.length === 1) {
            end = Number(endparts[0]) + 1
          } else {
            end = Number(endparts[1]) + 1
          }
        }

        $('#opcuaiiotinject-time-interval-time-end').val(end)
        $('#opcuaiiotinject-time-interval-time-start').val(start)
      }
    } else {
      repeattype = 'none'
    }

    $('.opcuaiiotinject-time-row').hide()
    $('#opcuaiiotinject-time-type-select').val(repeattype)
    $('#opcuaiiotinject-time-row-' + repeattype).show()

    $('#node-input-payload').typedInput('type', this.payloadType)

    $('#opcuaiiotinject-time-type-select').change()
    $('#opcuaiiotinject-time-interval-time-start').change()

    $('#node-input-injectType').change(function () {
      if ($(this).val() === 'listen') {
        $('#input-label-listener').show()
        $('#input-label-payload').hide()

        if(fieldPayloadType.val() !== 'num' && fieldPayloadType.val() !== 'json') {
            $('#node-input-payload').typedInput('type', 'num')
            $('#node-input-payload').val('1000')
        }
      } else {
        $('#input-label-payload').show()
        $('#input-label-listener').hide()
      }
    })

    $('#node-input-once').change(function () {

      if ($(this).is(':checked') || $('#opcuaiiotinject-time-type-select').val() !== 'none') {
        $('#node-delay').show()
      } else {
        $('#node-delay').hide()
      }
    })

    let tabs = RED.tabs.create({
      id: 'node-input-inject-tabs',
      onchange: function (tab) {
        $('#node-input-inject-tabs-content').children().hide()
        $('#' + tab.id).show()
      }
    })

    tabs.addTab({
      id: 'opcuaiiotinject-tab-settings',
      label: this._('opcuaiiotinject.tabs-label.settings')
    })

    tabs.addTab({
      id: 'opcuaiiotinject-tab-addressSpaceItems',
      label: this._('opcuaiiotinject.tabs-label.addressSpaceItems')
    })

    let cacheItemCount = 0
    if (node.addressSpaceItems && node.addressSpaceItems.length > 0) {
      cacheItemCount = node.addressSpaceItems.length
      node.addressSpaceItems.forEach(function (element, index, array) {
        generateItemsEntry(element, index)
      })
    }

    function generateItemsEntry (opcuaItem, id) {
      let container = $('<li/>', {
        style:
          'background: #fefefe; margin:0; padding:8px 0px; border-bottom: 1px solid #ccc;'
      })
      let row = $('<div class="row" id="row' + id + '" />').appendTo(container)

      $('<i style="color: #eee; cursor: move;" class="node-input-addressSpaceItems-handle fa fa-bars"></i>').appendTo(row)

      let itemNameField = $('<input/>', {
        class: 'addressSpaceItemName',
        id: 'node-input-addressSpaceItems-name' + id,
        type: 'text',
        style: 'margin: 0 auto;width:20%;min-width:60px;margin-left:5px',
        placeholder: 'Name'
      }).appendTo(row)

      let itemNodIdField = $('<input/>', {
        class: 'addressSpaceItemNodeId',
        id: 'node-input-addressSpaceItems-nodeId' + id,
        type: 'text',
        style: 'margin: 0 auto;width:43%;min-width:60px;margin-left:5px',
        placeholder: 'ns=0;i=85'
      }).appendTo(row)

      let itemDatatypeField = $('<input/>', {
        class: 'addressSpaceItemDatatype',
        id: 'node-input-addressSpaceItems-datatype' + id,
        type: 'text',
        style: 'margin: 0 auto;width:18%;min-width:60px;margin-left:5px',
        placeholder: 'optional'
      }).appendTo(row)

      itemNameField.val(opcuaItem.name)
      itemNodIdField.val(opcuaItem.nodeId)
      itemDatatypeField.val(opcuaItem.datatypeName)

      let finalspan = $('<span/>', {style: 'float: right;margin-right: 10px;'}).appendTo(row)

      let lookupItemButton = $('<a/>', {
        href: '#',
        id: 'node-button-inject-datatypes' + id,
        class: 'editor-button editor-button-small listButton',
        style: 'margin-top: 7px; margin-left: 5px;'
      }).appendTo(finalspan)

      lookupItemButton.click(function () {
        let datatypesLookupButton = $('#node-button-inject-datatypes' + id)
        let datatypeLookupField = $('#row' + id + ' #node-input-addressSpaceItems-datatype'  + id)

        datatypesLookupButton.addClass('disabled')

        $.getJSON('opcuaIIoT/plain/DataTypeIds', function (data) {
          datatypesLookupButton.removeClass('disabled')
          node.datatypeNames = []

          $.each(data, function (i, datatypeName) {
            node.datatypeNames.push(datatypeName)
          })

          datatypeLookupField.autocomplete({
            source: node.datatypeNames,
            minLength: 0,
            close: function (event, ui) {
              datatypeLookupField.autocomplete('destroy')
            }
          }).autocomplete('search', '')
        })
      })

      $('<i/>', {class: 'fa fa-search'}).appendTo(lookupItemButton)

      let removeItemButton = $('<a/>', {
        href: '#',
        id: 'node-button-inject-remove' + id,
        class: 'editor-button editor-button-small listButton',
        style: 'margin-top: 7px; margin-left: 5px;'
      }).appendTo(finalspan)

      $('<i/>', {class: 'fa fa-remove'}).appendTo(removeItemButton)

      removeItemButton.click(function () {
        container.fadeOut(300, function () {
          $(this).remove()
        })
      })

      $('#node-input-addressSpaceItems-container').append(container)
    }

    $('#node-input-addressSpaceItems-container').sortable({
      axis: 'y',
      handle: '.node-input-addressSpaceItems-handle',
      cursor: 'move'
    })

    $('#node-input-addressSpaceItems-container .node-input-addressSpaceItems-handle').disableSelection()

    $('#node-input-addressSpaceItems-add').click(function () {
      if(!cacheItemCount || cacheItemCount < 0) {
        cacheItemCount = 0
      }
      generateItemsEntry({name: '', nodeId: '', datatypeName: ''}, cacheItemCount++) // length is every time one more than index
      $('#node-input-addressSpaceItems-container-div').scrollTop($('#node-input-addressSpaceItems-container-div').get(0).scrollHeight)
    })

    function switchDialogResize () {
      let rows = $('#dialog-form>div:not(.node-input-addressSpaceItems-container-row)')
      let height = $('#dialog-form').height()

      rows.each(function (index, row) {
        height -= row.outerHeight(true)
      })

      let editorRow = $('#dialog-form>div.node-input-addressSpaceItems-container-row')
      height -= (parseInt(editorRow.css('marginTop')) + parseInt(editorRow.css('marginBottom')))
      $('#node-input-addressSpaceItems-container-div').css('height', height + 'px')
    }

    $('#dialog').on('dialogresize', switchDialogResize)

    $('#dialog').on('dialogopen', function (ev) {
      let size = $('#dialog').dialog('option', 'sizeCache-switch')
      if (size) {
        $('#dialog').dialog('option', 'width', size.width)
        $('#dialog').dialog('option', 'height', size.height)
        switchDialogResize()
      } else {
        setTimeout(switchDialogResize, 10)
      }
    })

    $('#dialog').on('dialogclose', function (ev, ui) {
      $('#dialog').off('dialogresize', switchDialogResize)
    })

    // console.log('well done editprepare ...')
  }
  injectNode.oneditsave = function () {
    let node = this
    let repeat = ''
    let crontab = ''
    let type = $('#opcuaiiotinject-time-type-select').val()

    if (type === 'interval') {
      crontab = ''
      let count = $('#opcuaiiotinject-time-interval-count').val()
      let units = $('#opcuaiiotinject-time-interval-units').val()

      if (units === 's') {
        repeat = count
      } else {
        if (units === 'n') {
          repeat = count / 1000
        } else if (units === 'm') {
          repeat = count * 60
        } else if (units === 'h') {
          repeat = count * 60 * 60
        }
      }
    } else if (type === 'interval-time') {
      repeat = ''
      let count = $('#opcuaiiotinject-time-interval-time-units').val()
      let startTime = Number($('#opcuaiiotinject-time-interval-time-start').val())
      let endTime = Number($('#opcuaiiotinject-time-interval-time-end').val())

      let days = $('#opcuaiiotinject-time-interval-time-days  input[type=checkbox]:checked').map(function (_, el) {
        return $(el).val()
      }).get()

      if (days.length === 0) {
        crontab = ''
      } else {
        if (days.length === 7) {
          days = '*'
        } else {
          days = days.join(',')
        }

        let timerange = ''

        if (endTime === 0) {
          timerange = startTime + '-23'
        } else if (startTime + 1 < endTime) {
          timerange = startTime + '-' + (endTime - 1)
        } else if (startTime + 1 === endTime) {
          timerange = startTime
        } else {
          let startpart = ''
          let endpart = ''

          if (startTime === 23) {
            startpart = '23'
          } else {
            startpart = startTime + '-23'
          }

          if (endTime === 1) {
            endpart = '0'
          } else {
            endpart = '0-' + (endTime - 1)
          }

          timerange = startpart + ',' + endpart
        }

        if (count === '0') {
          crontab = count + ' ' + timerange + ' * * ' + days
        } else {
          crontab = '*/' + count + ' ' + timerange + ' * * ' + days
        }
      }
    } else if (type === 'time') {
      let time = $('#opcuaiiotinject-time-time').val()
      let days = $('#opcuaiiotinject-time-time-days  input[type=checkbox]:checked').map(function (_, el) {
        return $(el).val()
      }).get()

      if (days.length === 0) {
        crontab = ''
      } else {
        if (days.length === 7) {
          days = '*'
        } else {
          days = days.join(',')
        }

        let parts = time.split(':')
        repeat = ''
        crontab = parts[1] + ' ' + parts[0] + ' * * ' + days
      }
    }

    $('#node-input-repeat').val(repeat)
    $('#node-input-crontab').val(crontab)

    let cacheItems = $('#node-input-addressSpaceItems-container').children()
    node.addressSpaceItems = []

    cacheItems.each(function () {
        node.addressSpaceItems.push({
          name: $(this).find('.addressSpaceItemName').val(),
          nodeId: $(this).find('.addressSpaceItemNodeId').val(),
          datatypeName: $(this).find('.addressSpaceItemDatatype').val()
        })
    })

    // console.log('well done editsave ...')
  }
  injectNode.label = function () {
    let suffix = ''

    if (this.once) {
      suffix = ' ¹'
    }

    let hasRepeat = ( this.repeat && this.repeat !== 'none' )
    if (hasRepeat || this.crontab) {
      suffix = suffix + ' ↻'
    }

    if (this.name) {
      return this.name + suffix
    }

    switch (this.payloadType) {
      case 'string':
      case 'str':
      case 'num':
      case 'bool':
      case 'json':
        if (this.topic !== '' && (this.topic.length + this.payload.length) <= 32) {
          return this.topic + ':' + this.payload + suffix
        } else if (this.payload.length > 0 && this.payload.length < 24) {
          return this.payload + suffix
        }
        return this._('opcuaiiotinject.inject') + suffix
      case 'date':
        if (this.topic !== '' && this.topic.length <= 16) {
          return this.topic + ':' + this._('opcuaiiotinject.timestamp') + suffix
        }
        return this._('opcuaiiotinject.timestamp') + suffix
      default:
        if (this.payloadType === 'flow' && this.payload.length < 19) {
          return 'flow.' + this.payload + suffix
        } else if (this.payloadType === 'global' && this.payload.length < 17) {
          return 'global.' + this.payload + suffix
        }
        return this._('opcuaiiotinject.inject') + suffix
    }
  }

  injectNode.labelStyle = function () {
    return this.name ? 'node_label_italic' : ''
  }
</script>

<script type="text/x-red" data-template-name="OPCUA-IIoT-Inject">
    <div class="form-row">
        <ul style="background: #fff; min-width: 600px; margin-bottom: 20px;" id="node-input-inject-tabs"></ul>
    </div>
    <div id="node-input-inject-tabs-content" style="min-height: 170px;">
        <div id="opcuaiiotinject-tab-settings" style="display:none">
            <div class="form-row" id="node-inject-type">
                <label for=""><i class="fa fa-list"></i> <span data-i18n="opcuaiiotinject.label.injectType"></span></label>
                <select id="node-input-injectType" type="text" style="width:140px;">
                    <option value="inject" data-i18n="opcuaiiotinject.type-label.inject"></option>
                    <option value="read" data-i18n="opcuaiiotinject.type-label.read"></option>
                    <option value="write" data-i18n="opcuaiiotinject.type-label.write"></option>
                    <option value="listen" data-i18n="opcuaiiotinject.type-label.listen"></option>
                </select>
            </div>

            <div class="form-row" id="input-payload-row">
                <label for="node-input-payload"><i class="fa fa-envelope"></i>
                <span id="input-label-payload" data-i18n="opcuaiiotinject.label.payload"></span>
                <span id="input-label-listener" data-i18n="opcuaiiotinject.label.interval"></span>
                </label>
                <input type="text" id="node-input-payload" style="width:70%">
                <input type="hidden" id="node-input-payloadType">
            </div>

            <div class="form-row">
                <label for="node-input-topic"><i class="icon-tag"></i> <span data-i18n="node-red:common.label.topic"></span></label>
                <input type="text" id="node-input-topic">
            </div>

            <div class="form-row" id="node-delay">
                <label for="node-input-startDelay"><i class="fa fa-clock-o"></i> <span data-i18n="opcuaiiotinject.startDelay"></span></label>
                <input type="text" id="node-input-startDelay" placeholder="10" style="width:60px"> <span data-i18n="opcuaiiotinject.startDelayAddon"></span>
            </div>

            <div class="form-row" id="node-once">
                <label for="node-input-once" style="width:160px">
                <i class="fa fa-power-off"></i> <span data-i18n="opcuaiiotinject.onstart"></span></label>
                <input type="checkbox" id="node-input-once" style="width:40px">
            </div>

            <div class="form-row">
                <label for=""><i class="fa fa-repeat"></i> <span data-i18n="opcuaiiotinject.label.repeat"></span></label>
                <select id="opcuaiiotinject-time-type-select">
                    <option value="none" data-i18n="opcuaiiotinject.none"></option>
                    <option value="interval" data-i18n="opcuaiiotinject.interval"></option>
                    <option value="interval-time" data-i18n="opcuaiiotinject.interval-time"></option>
                    <option value="time" data-i18n="opcuaiiotinject.time"></option>
                </select>
                <input type="hidden" id="node-input-repeat">
                <input type="hidden" id="node-input-crontab">
            </div>

            <div class="form-row opcuaiiotinject-time-row hidden" id="opcuaiiotinject-time-row-interval">
                <span data-i18n="opcuaiiotinject.every"></span>
                <input id="opcuaiiotinject-time-interval-count" class="opcuaiiotinject-time-count" value="500"></input>
                <select style="width:140px" id="opcuaiiotinject-time-interval-units">
                    <option value="n" data-i18n="opcuaiiotinject.milliseconds"></option>
                    <option value="s" data-i18n="opcuaiiotinject.seconds"></option>
                    <option value="m" data-i18n="opcuaiiotinject.minutes"></option>
                    <option value="h" data-i18n="opcuaiiotinject.hours"></option>
                </select><br/>
            </div>

            <div class="form-row opcuaiiotinject-time-row hidden" id="opcuaiiotinject-time-row-interval-time">
                <span data-i18n="opcuaiiotinject.every"></span> <select style="width:90px" id="opcuaiiotinject-time-interval-time-units" class="opcuaiiotinject-time-int-count" value="1">
                    <option value="1">1</option>
                    <option value="2">2</option>
                    <option value="3">3</option>
                    <option value="4">4</option>
                    <option value="5">5</option>
                    <option value="6">6</option>
                    <option value="10">10</option>
                    <option value="12">12</option>
                    <option value="15">15</option>
                    <option value="20">20</option>
                    <option value="30">30</option>
                    <option value="0">60</option>
                </select> <span data-i18n="opcuaiiotinject.minutes"></span><br/>
                <span data-i18n="opcuaiiotinject.between"></span> <select id="opcuaiiotinject-time-interval-time-start" class="opcuaiiotinject-time-times"></select>
                <span data-i18n="opcuaiiotinject.and"></span> <select id="opcuaiiotinject-time-interval-time-end" class="opcuaiiotinject-time-times"></select><br/>
                <div id="opcuaiiotinject-time-interval-time-days" class="opcuaiiotinject-time-days">
                    <div style="display: inline-block vertical-align: topmargin-right:5px" data-i18n="opcuaiiotinject.on">on</div>
                    <div style="display:inline-block">
                        <div>
                            <label><input type='checkbox' checked value='1'/> <span data-i18n="opcuaiiotinject.days.0"></span></label>
                            <label><input type='checkbox' checked value='2'/> <span data-i18n="opcuaiiotinject.days.1"></span></label>
                            <label><input type='checkbox' checked value='3'/> <span data-i18n="opcuaiiotinject.days.2"></span></label>
                        </div>
                        <div>
                            <label><input type='checkbox' checked value='4'/> <span data-i18n="opcuaiiotinject.days.3"></span></label>
                            <label><input type='checkbox' checked value='5'/> <span data-i18n="opcuaiiotinject.days.4"></span></label>
                            <label><input type='checkbox' checked value='6'/> <span data-i18n="opcuaiiotinject.days.5"></span></label>
                        </div>
                        <div>
                            <label><input type='checkbox' checked value='0'/> <span data-i18n="opcuaiiotinject.days.6"></span></label>
                        </div>
                    </div>
                </div>
            </div>

            <div class="form-row opcuaiiotinject-time-row hidden" id="opcuaiiotinject-time-row-time">
                <span data-i18n="opcuaiiotinject.at"></span> <input id="opcuaiiotinject-time-time" value="12:00"></input><br/>
                <div id="opcuaiiotinject-time-time-days" class="opcuaiiotinject-time-days">
                    <div style="display: inline-block vertical-align: topmargin-right: 5px">on </div>
                    <div style="display:inline-block">
                        <div>
                            <label><input type='checkbox' checked value='1'/> <span data-i18n="opcuaiiotinject.days.0"></span></label>
                            <label><input type='checkbox' checked value='2'/> <span data-i18n="opcuaiiotinject.days.1"></span></label>
                            <label><input type='checkbox' checked value='3'/> <span data-i18n="opcuaiiotinject.days.2"></span></label>
                        </div>
                        <div>
                            <label><input type='checkbox' checked value='4'/> <span data-i18n="opcuaiiotinject.days.3"></span></label>
                            <label><input type='checkbox' checked value='5'/> <span data-i18n="opcuaiiotinject.days.4"></span></label>
                            <label><input type='checkbox' checked value='6'/> <span data-i18n="opcuaiiotinject.days.5"></span></label>
                        </div>
                        <div>
                            <label><input type='checkbox' checked value='0'/> <span data-i18n="opcuaiiotinject.days.6"></span></label>
                        </div>
                    </div>
                </div>
            </div>

            <div class="form-row">
                <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
                <input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
            </div>

            <div class="form-tips" data-i18n="[html]opcuaiiotinject.tip"></div>
        </div>
        <div id="opcuaiiotinject-tab-addressSpaceItems" style="display:none">
            <div class="form-row node-input-addressSpaceItems-container-row" style="margin-bottom: 0px;">
                <div id="node-input-addressSpaceItems-container-div"
                    style="box-sizing: border-box; border-radius: 5px;
                    height: 480px; padding: 5px; border: 1px solid #ccc; overflow-y:scroll;">
                    <ol id="node-input-addressSpaceItems-container" style="list-style-type:none;margin:0 auto;width:95%;margin-left:20px"></ol>
                </div>
            </div>
            <div class="form-row">
                <a href="#" class="editor-button editor-button-small" id="node-input-addressSpaceItems-add"
                style="margin-top: 4px;"><i class="fa fa-plus"></i>
                <span data-i18n="opcuaiiotinject.label.addButton"></span></a>
            </div>
        </div>
    </div>

</script>

<script type="text/x-red" data-help-name="OPCUA-IIoT-Inject">
    <h2>OPC UA IIoT Inject</h2>

    <p>The modified Inject node is designed to provide some unique features you need to create beautiful flows.</p>

    <p>Pressing the button on the left side of the node builds an inject object to read, browse, listen or write by
    the OPC UA IIoT nodes.</p>

    <h2>Configuration</h2>

    <h3>Tab Settings</h3>

    <strong>Type</strong>
    <p>Set that type to prepare the correct value for injects.</p>

    <strong>Payload/Interval</strong>
    <p>There is an option to send a JSON payload inject into the Listener.</p>
    <p>Example:</p>
    <p><pre>{ "interval": 500, "queueSize": 10 }</pre></p>

    <div>
        <h5>msg.payload.options<h5>

        <strong>event subscription parameters default:</stong>
        <pre>
        msg.payload.options = {
            requestedPublishingInterval: 100,
            requestedLifetimeCount: 60,
            requestedMaxKeepAliveCount: 10,
            maxNotificationsPerPublish: 4,
            publishingEnabled: true,
            priority: 3
        }
        </pre>

        <strong>subscription parameters default:</stong>
        <pre>
        msg.payload.options = {
            requestedPublishingInterval: 100,
            requestedLifetimeCount: 1000,
            requestedMaxKeepAliveCount: 12,
            maxNotificationsPerPublish: 100,
            publishingEnabled: true,
            priority: 6
        }
        </pre>
    </div>
    <p>If the Inject-Type is set to read/write, then the value is a standard payload to transport your data.</p>

    <strong>Topic</strong>
    <p>The topic is to group for queues or protocols like MQTT.</p>

    <strong>Repeat</strong>
    <p>With the repeat settings you can set a cron configuration.</p>
    <p>The interval settings needs a short delay on start. This is equal to the once option but without any inject at to start working.</p>

    <strong>Inject once at start</strong>
    <p>The 'Delay sec. at start' has to be set to a minimum for starting injects toward the OPC UA server.</p>
    <p>All activities will start ever <strong>after</strong> the start inject is done.</p>

    <p>I did a contribute to Node-RED to provide that delay at start from Node-RED 0.18 inject too.</p>

    <strong>Name</strong>
    <p>Name in the flow of Node-RED.</p>

    <h3>Tab OPC UA Items</h3>

    <strong>Name (optional)</strong>
    <p>A short human readable name for long or numeric nodeId's.</p>

    <strong>Node-Id (mandatory)</strong>
    <p>The Node-Id has to be an OPC UA valid Node-Id like ns=0;i=85 (root->Objects)</p>
    <p>You can use our Browser node for OPC UA to find the correct Node-Id.</p>

    <strong>Data Type (mandatory/optional)</strong>
    <p>The Data Type setting is needed to do the converts of the node-opcua Variant type result(s).</p>
    <p>It is mandatory to write data otherwise it is optional!</p>
    <p>In best practice do transformations with the Result Filter node.</p>

    <div>
        <strong>Content of an inject:</strong>

        <ul>
            <li>payload (value or options for listener)
            <li>topic
            <li>nodetype (inject, read, write, listen)
            <li>injectType (inject)
            <li>addressSpaceItems (Array of nodeId's)
        </ul>
     </div>

</script>
